#include <vector>
#include <algorithm>
#include <cmath>
#include <chrono>
#include <thread>
#include "constants.h"
#include "data_io.h"
#include "tools.h"

using namespace std;

StdNormalizer &StdNormalizer::add(double x)
{
    this->is_initeed = false;

    this->n++;
    this->sum += x;
    this->square_sum += (x * x);
    return *this;
}

StdNormalizer &StdNormalizer::drop(double x)
{
    this->is_initeed = false;

    this->n--;
    this->sum -= x;
    this->square_sum -= (x * x);
    return *this;
}

double StdNormalizer::transform(double x)
{
    if (this->is_initeed)
    {
        return (x - this->mean) / this->std;
    }
    else
    {
        this->mean = this->sum / this->n;
        double var = (this->square_sum / this->n) - (this->mean * this->mean); // 方差 = 平方的均值减去均值的平方
        this->std = sqrt(var) + 0.0001;

        this->is_initeed = true;
        return this->transform(x);
    }
}

void process_overflow_t(TAssign *tassign)
{
    tassign->refresh_inherited_bw();
    tassign->refresh_total_bw();

    bool not_finish = true;
    while (not_finish)
    {
        not_finish = false;
        for (int site_id = 0; site_id < N; site_id++)
        {
            if (tassign->site_total_bw[site_id] > site_info.site_bw_upper[site_id])
            {
                // #ifndef RELEASE
                //                 cout << "over flow t:" << tassign->t << " site_id:" << site_id << " bw:" << tassign->site_total_bw[site_id] - site_info.site_bw_upper[site_id] << endl;
                // #endif
                not_finish = true;
                SiteAlloSortIter site_allo_sort_iter(tassign->site_stream_to_allo_info[site_id], true);

                AlloNode *min_node;

                site_allo_sort_iter.next(min_node);
                while ((min_node) && (tassign->site_total_bw[site_id] > site_info.site_bw_upper[site_id]))
                {
                    const int &client_id = min_node->client_id;
                    int transfer_site_id = -1;

                    vector<int> &selectable_site_ids = client_info.client_to_sites[client_id];
                    for (int _i = 0; _i < 8; _i++)
                    {
                        int &_site_id = rand_choice_of<int>(selectable_site_ids.begin(), selectable_site_ids.size());
                        if (_site_id != site_id)
                        {
                            transfer_site_id = _site_id;
                            break;
                        }
                    }

                    if (transfer_site_id != -1)
                    {
                        tassign->transfer(min_node->stream_id, client_id, transfer_site_id);
                    }
                    site_allo_sort_iter.next(min_node);
                }
            }
        }
    }
};

double get_edge_site_score(const int &edge_site_bw, const int &site_bw_upper)
{
    if (edge_site_bw == 0)
    {
        return 0.0;
    }
    double edge_site_score = config_info.base_cost;
    if (edge_site_bw > config_info.base_cost)
    {
        double site_bw_v_diff = edge_site_bw - config_info.base_cost;
        edge_site_score = (site_bw_v_diff * site_bw_v_diff) / site_bw_upper + edge_site_bw;
    }
    return edge_site_score;
}

double get_center_site_score(const long long &center_site_bw)
{
    return center_site_bw * config_info.center_cost;
}

void get_quantile_t(AssignInfo &assign_info, int (&edge_site_quantile_t)[MAX_N], int &center_site_quantile_t)
{
    for (int site_id = 0; site_id < N; site_id++)
    {
        int sort_list[T];
        for (int t = 0; t < T; t++)
        {
            sort_list[t] = assign_info.assign_vec[t]->site_total_bw[site_id];
        }
        vector<int> sotred_index = arg_sort(sort_list, T, true);
        edge_site_quantile_t[site_id] = sotred_index[config_info.quantile_index];
    }
    long long sort_list[T];
    for (int t = 0; t < T; t++)
    {
        sort_list[t] = assign_info.assign_vec[t]->center_site_bw;
    }
    vector<int> sotred_index = arg_sort(sort_list, T, true);
    center_site_quantile_t = sotred_index[config_info.quantile_index];
}

void show_score(AssignInfo &assign_info)
{
    if (RELEASE_MODE)
    {
        return;
    }
    double edge_site_score = 0.0;
    for (int site_id = 0; site_id < N; site_id++)
    {
        int sort_list[T];
        for (int t = 0; t < T; t++)
        {
            sort_list[t] = assign_info.assign_vec[t]->site_total_bw[site_id];
        }

        sort(sort_list, sort_list + T);

        int nine_five_bandwidth = sort_list[config_info.quantile_index];
        edge_site_score += get_edge_site_score(nine_five_bandwidth, site_info.site_bw_upper[site_id]);
    }

    long long sort_list[T];
    for (int t = 0; t < T; t++)
    {
        sort_list[t] = assign_info.assign_vec[t]->center_site_bw;
    }
    sort(sort_list, sort_list + T);

    long long nine_five_bandwidth = sort_list[config_info.quantile_index];
    double center_site_score = get_center_site_score(nine_five_bandwidth);

    double total_score = edge_site_score + center_site_score;
    cout << "total_score:" << (long long)total_score << " edge_site_score:" << (long long)edge_site_score << " center_site_score:" << (long long)center_site_score << endl;
}

void show_center_cost_detail(TAssign *tassign, int site_id, int stream_id, int top_n, bool show_stream_detail)
{
    int site_min, site_max = site_id;
    int stream_min, stream_max = stream_id;
    if (site_id == -1)
    {
        site_min = 0;
        site_max = N - 1;
    }
    if (stream_id == -1)
    {
        stream_min = 0;
        stream_max = tassign->P - 1;
    }
    if (top_n == -1)
    {
        top_n = N;
    }

    long long tassign_center_score = 0;
    vector<long long> center_cost_of_edge_sites(N, 0);

    for (int current_site_id = site_min; current_site_id <= site_max; ++current_site_id)
    {
        long long &site_center_score = center_cost_of_edge_sites[current_site_id];
        for (int current_stream_id = stream_min; current_stream_id <= stream_max; ++current_stream_id)
        {
            site_center_score += tassign->site_stream_to_allo_info[current_site_id][current_stream_id].largest_bw;
        }
        tassign_center_score += site_center_score;
    }
    cout << "**********************************  中心节点总带宽为：" << tassign_center_score << "  **********************************" << endl;

    vector<int> sorted_site_ids = arg_sort(center_cost_of_edge_sites.begin(), N, false);
    int top_i = 0;
    for (const int &current_site_id : sorted_site_ids)
    {
        if ((current_site_id >= site_min) && (current_site_id <= site_max) && (center_cost_of_edge_sites[current_site_id]))
        {
            if (top_i == top_n)
            {
                break;
            }
            cout << endl;
            cout << "*************** 当前是引起中心节点损失Top <" << ++top_i << "> 节点"
                 << ", site_id=" << current_site_id
                 << ", cost=" << center_cost_of_edge_sites[current_site_id]
                 << " *******************"
                 << endl;
            if (show_stream_detail)
            {
                vector<int> center_cost_of_streams(tassign->P, 0);
                for (int current_stream_id = stream_min; current_stream_id <= stream_max; ++current_stream_id)
                {
                    center_cost_of_streams[current_stream_id] = tassign->site_stream_to_allo_info[current_site_id][current_stream_id].largest_bw;
                }
                vector<int> sorted_stream_ids = arg_sort(center_cost_of_streams.begin(), tassign->P, false);
                for (const int &current_stream_id : sorted_stream_ids)
                {
                    if ((current_stream_id >= stream_min) && (current_stream_id <= stream_max) && (tassign->site_stream_to_allo_info[current_site_id][current_stream_id].count))
                    {
                        AlloNode *iter = tassign->site_stream_to_allo_info[current_site_id][current_stream_id].head;
                        cout << "<site_id:" << current_site_id << "> 当前流ID是：" << current_stream_id << " 流列表为：";

                        cout << " [client:" << iter->client_id << ", bw:" << iter->bandwidth << "]";
                        iter = iter->next_site_allo;

                        while (iter)
                        {
                            cout << " --> [client:" << iter->client_id << ", bw:" << iter->bandwidth << "]";
                            iter = iter->next_site_allo;
                        }
                        cout << endl;
                    }
                }
            }
        }
    }
}

void show_center_cost_detail(TAssign *tassign)
{
    show_center_cost_detail(tassign, -1, -1, -1, true);
}
void show_center_cost_detail(TAssign *tassign, int top_n)
{
    show_center_cost_detail(tassign, -1, -1, top_n, true);
}
void show_center_cost_detail(TAssign *tassign, bool show_stream_detail)
{
    show_center_cost_detail(tassign, -1, -1, -1, show_stream_detail);
}
void show_center_cost_detail(TAssign *tassign, int site_id, int stream_id)
{
    show_center_cost_detail(tassign, site_id, stream_id, -1, true);
}

void check_solution(AssignInfo &assign_info)
{
    if (RELEASE_MODE)
    {
        return;
    }

    int site_total_bw[N] = {0};

    for (int t = 0; t < T; t++)
    {
        TAssign *tassign = assign_info.assign_vec[t];
        TDemand *tdemand = demand_info.demand_vec[t];
        int P = tdemand->P;

        for (int stream_id = 0; stream_id < P; stream_id++)
        {
            for (int client_id = 0; client_id < M; client_id++)
            {
                int site_id = tassign->stream_client_to_allo_node[stream_id][client_id].site_id;
                int bw = tdemand->demand_bw_matrix[stream_id][client_id];
                if (bw && (site_id == -1))
                {
                    cout << "ERROR: 需求未被满足"
                         << " t=" << t
                         << " stream=" << stream_id
                         << " client=" << client_id
                         << endl;
                    throw exception();
                }

                if ((site_id != -1) && (!site_info.site_reachable_matrix[site_id][client_id]))
                {
                    cout << "ERROR: 不可达分配"
                         << " t=" << t
                         << " site=" << site_id
                         << " client=" << client_id
                         << endl;
                    throw exception();
                }
                site_total_bw[site_id] += bw;
            }
        }

        for (int site_id = 0; site_id < N; site_id++)
        {
            if (site_total_bw[site_id] > site_info.site_bw_upper[site_id])
            {
                cout << "ERROR: 分配超上限"
                     << " t=" << t
                     << " site=" << site_id
                     << " site_total_bw=" << site_total_bw[site_id]
                     << " site_bw_upper=" << site_info.site_bw_upper[site_id]
                     << endl;
                throw exception();
            }

            site_total_bw[site_id] = floor(site_total_bw[site_id] * INHERIT_RATE);
        }
    }
    cout << "分配方案合法" << endl;
}

void assert(bool condition)
{
    if (condition)
    {
        this_thread::sleep_for(chrono::seconds(500));
    }
    else
    {
        throw exception();
    }
}